/**
 * @options 参数说明:
 * options.step = 飞行轨迹数目, 默认5
 * options.waitTimeout = 鼠标移动到trigger上等待的时间,默认200ms
 * options.align = panel 的飞行方向
 */
function TBFlyPanel(panel, trigger, options) {
	this.panel = (typeof(panel)=="string")?document.getElementById(panel):panel;
	this.trigger = (typeof(trigger)=="string")?document.getElementById(trigger):trigger;
	this.options = options || {};
	this._panelWH = [];
	this._animateData = [];
	this._flyOutTimeoutId = null;
	this._flyOffTimeoutId = null;
	this._flying = false;
	this._panelDisplayed = false;
	var _animate = (function(fp) {
		var animate = function(callback) {
			this.callback = callback;
			this.count = 0;
			this.play();
		}
		animate.prototype.play = function() {
			var data = fp._animateData;
			var fpd = data[this.count], fps = fp.panel.style;
			fps.left = fpd[0] + 'px';
			fps.top = fpd[1] + 'px';
			fps.width = fpd[2] + 'px';
			fps.height = fpd[3] + 'px';
			this.count++;
			if (this.count == data.length) {
				if (this.callback) this.callback(fp);
				return;
			} else {
				var self = this;
				setTimeout(function(){self.play()}, 15);
			}
		}
		return animate;
	})(this);
	this._init();
	this._fly = function(cb) { new _animate(cb); };
	this.panel['_fp'] = this.trigger['_fp'] = this;
	this.trigger.onmouseover = TBFlyPanel._triggerMover;
	this.trigger.onmouseout = TBFlyPanel._triggerMout;
	this.trigger.onclick = function(){return false;};
	this.trigger.onfocus = TBFlyPanel._triggerMover;
	this.panel.onmouseout = TBFlyPanel._panelMout;
	this.panel.onmouseover = TBFlyPanel._panelMover;
}
TBFlyPanel.prototype._init = function() {
	this.panel.style.position = 'absolute';
	this.panel.style.top = this.panel.style.left = '-5000px';
	this.panel.style.display = 'block';
	this._panelWH[0] = this.panel.offsetWidth; 
	this._panelWH[1] = this.panel.offsetHeight;
	this.panel.style.display = 'none';
}
/* 计算飞行数据 */
TBFlyPanel.prototype._computeAnimateData = function() {
	var pw = this._panelWH[0], ph = this._panelWH[1];
	var dw = document.body.clientWidth;
	var tw = this.trigger.offsetWidth, th = this.trigger.offsetHeight;
	var pos = TBFlyPanel.getPosXY(this.trigger);
	var sl = pos[0], st = pos[1];
	var sl2, st2;
	var align = this.options.align || 'center';
	if ('center' == align) {
		sl2 = pos[0]-(pw-tw)/2;
		if (sl2 + pw > dw) sl2=dw-pw;
		st2 = pos[1] + th;
	} else if ('left' == align) {
		sl2 = pos[0]-(pw-tw);
		if (sl2 < 0) sl2 = 0;
		st2 = pos[1] + th;
	} else if ('right' == align) {
		sl2 = pos[0];
		if (sl2 + pw > dw) sl2=dw-pw;
		st2 = pos[1] + th;
	}
	var fpd = this._animateData;
	fpd.length = 0; //clean last data
	var step = this.options.step || 5;
	fpd[0] = [sl, st, tw, th];
	fpd[step] = [sl2, st2, pw, ph];
	for (var i = 1; i < step; i++) {
		fpd[i] = [];
		fpd[i][0] = sl - (sl-sl2)*i/step;
		fpd[i][1] = st - (st-st2)*i/step;
		fpd[i][2] = tw + (pw-tw)*i/step;
		fpd[i][3] = th + (ph-th)*i/step;
	}
}
/* 显示|隐藏 panel 的内容 */
TBFlyPanel.prototype._toggleVisible = function() {
	for (var i = 0, n = this.panel.childNodes; i < n.length; i++) {
		if (n[i].nodeType != 1) continue;
		var v = n[i].style.visibility;
		n[i].style.visibility = (v != 'hidden')?'hidden':'visible';
	}
}
/* 显示|隐藏 panel 的内容 */
TBFlyPanel.prototype.flyOut = function() {
	this._flyOutTimeoutId = null;
	this._computeAnimateData();
	this._flying = true;
	this._toggleVisible();
	this.panel.style.display = 'block';
	this._fly(function(fp) {
		fp._toggleVisible();
		fp._flying = false;
		fp._panelDisplayed = true;
	});
}
TBFlyPanel.prototype.flyOff = function() {
	this._toggleVisible();
	this._flying = true;
	this._animateData.reverse();
	this._fly(function(fp) {
		fp._toggleVisible();
		fp._flying = false;
		fp._panelDisplayed = false;
		fp.panel.style.display = 'none';
	});
}
TBFlyPanel.checkContains = function(p, c){
	if (p.contains)
		return p.contains(c);
	else {
		while(c){
			if(c==p) return true;
			c=c.parentNode;
		}
		return false;
	}
}
TBFlyPanel._triggerMover = function(e) {
	var target = !e ? event.srcElement : e.target;
	var self = target['_fp'];
	if (self._flyOutTimeoutId || self._panelDisplayed || self._flying)
		return;
	self._flyOutTimeoutId = setTimeout(function(){self.flyOut()}, self.options.waitTimeout || 200);
};
TBFlyPanel._triggerMout = function(e) {
	var evt = !e? window.event : e;
	var target = evt.srcElement || evt.target;
	while (!target['_fp']) {
		target = target.parentNode;
		if (target.tagName.toUpperCase == 'BODY') break;
	}
	var self = target['_fp'];
	/* 鼠标移动到trigger上紧接着panel飞动时鼠标临时在panel上或用户移动鼠标到panel上, 可能触发此事件, 忽略它 */
	var relatedTarget = evt.toElement || evt.relatedTarget;
	if (relatedTarget == self.panel || TBFlyPanel.checkContains(self.panel, relatedTarget))
		return;
	if (self._flyOutTimeoutId) {
		clearTimeout(self._flyOutTimeoutId);
		self._flyOutTimeoutId = null;
	} else {
		self._flyOffTimeoutId = setTimeout(function(){self.flyOff()}, 200);
	}
}
TBFlyPanel._panelMover = function(e) {
	var evt = !e? window.event : e;
	var target = !e? evt.srcElement : evt.target;
	var self = target['_fp'];
	if (!self) return;
	clearTimeout(self._flyOffTimeoutId);
}
TBFlyPanel._panelMout = function(e) {
	var evt = !e? window.event : e;
	var panel = !e? evt.srcElement : evt.target;
	while (!panel['_fp']) {
		panel = panel.parentNode;
		if (panel.tagName.toUpperCase == 'BODY') break;
	}
	var self = panel['_fp'];
	if (!self) return;
	var relatedTarget = evt.toElement || evt.relatedTarget;
	if (relatedTarget == self.trigger || TBFlyPanel.checkContains(panel, relatedTarget))
		return;
	if (self._flyOutTimeoutId) {
		clearTimeout(self._flyOutTimeoutId);
		self._flyOutTimeoutId = null;
	} else {
		self._flyOffTimeoutId = setTimeout(function(){self.flyOff()}, 200);
	}
}
TBFlyPanel.getPosXY = function(a, offset) {
	var p=offset?offset.slice(0):[0,0],tn;
	while(a) {
		tn=a.tagName.toUpperCase();
		p[0]+=a.offsetLeft-(tn=="DIV"&&a.scrollLeft?a.scrollLeft:0);
		p[1]+=a.offsetTop-(tn=="DIV"&&a.scrollTop?a.scrollTop:0);
		if (tn=="BODY") break;
		a=a.offsetParent;
	}
	return p;
}